home *** CD-ROM | disk | FTP | other *** search
- /*
- File: PrinterClassDriver.c
-
- Contains: MacOS USB printer class driver
- [ref. IEEE Std 1284-1994]
-
- Version: xxx put version here xxx
-
-
-
- Copyright: 1998 by Apple Computer, Inc., all rights reserved.
-
- */
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- includes
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- #include <Devices.h>
- #include <DriverServices.h>
- #include <Interrupts.h>
- #include <LowMem.h>
- #include <Folders.h>
- #include <String.h>
- #include <stdio.h>
- #include <USB.h>
-
- #ifndef __CODEFRAGMENTS__
- #include <codefragments.h>
- #endif
-
- #include "PrinterClassDriver.h"
- #include "TradDriverLoaderLib.h"
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- constants
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- #define MAX_SUFFIX 127 // maximum copies we'll enter in unit table
- #define kUSBParallelDrvrRsrcID 12
- #define kMinDrvrUnitNumber 48 // minimum unit table entry which we'll install
- #define kUSS720MillisecondDelay 3*1000 // poll every three seconds
- #define kUSS720StatusMSDelay 10 // poll one hundred times per second
- #define MAX_USB_TRANSFER_SIZE TRANSFER_SIZE // zero acts as manifest for conditional compilation
-
- #define kUSBAttributeBulk 0x02
- #define kUSBInputEndpointMask 0x80
-
- enum
- {
- kCString = 0, // StateStr, USBStatusStr selector
- kPString, // StateStr, USBStatusStr selector
- kDrvrFirstDigit = 5 // length_byte + ".USB" = 5
- };
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- manifest constants
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- //
- // DEBUGGING extra debugging information to USB Expert Log
- // DOUBLE_BUFFER use a page aligned buffer in system heap to double buffer app i/o
- // LOG echo all the write data to a log file in the system folder
- // LOCK_MEMORY LockMemory on the i/o buffer before write and unlock on write completion
- // VIRTUAL_MEMORY_CHECK check the physical addresses of the buffer we pass for write requests
- // MACSBUG_ON_READ break into MacsBug before each read request
- // MACSBUG_ON_READ_COMPLETE break into MacsBug at each read completion routine
- // MACSBUG_ON_WRITE break into MacsBug on each write request
- // MACSBUG_ON_WRITE_COMPLETE break into MacsBug at each write completion routine
- //
- #define DEBUGGING 0 /* DEBUGGING */
- #define DOUBLE_BUFFER 1 /* DOUBLE_BUFFER */
- #define LOG 0 /* LOG */
- #define LOCK_MEMORY 1 /* LOCK_MEMORY */
- #define MACSBUG_ON_READ 1 /* MACSBUG_ON_READ */
- #define MACSBUG_ON_READ_COMPLETE 0 /* MACSBUG_ON_READ_COMPLETE */
- #define MACSBUG_ON_WRITE 1 /* MACSBUG_ON_WRITE */
- #define MACSBUG_ON_WRITE_COMPLETE 0 /* MACSBUG_ON_WRITE_COMPLETE */
- #define VIRTUAL_MEMORY_CHECK 0 /* VIRTUAL_MEMORY_CHECK require LOCK_MEMORY, currently broken */
-
- #if LOG
- #define LOGGING(x) x
- #include <stdio.h>
- #else
- #define LOGGING(x)
- #endif
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- globals
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static struct usbPrinterPBStruct printerClassRecord;
- static FSSpec printerClassDriverFileSpec;
- LOGGING( static FILE *logfile );
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- prototypes
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
- static void PrinterDeviceCompletionProc(USBPB *pb);
- static void SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb );
- static void SoftReset( USBPB *usbprint, short interfaceNum );
- static void CapabilityRequest( USBPB *pb, Ptr p, long length, short config, short interfaceNum, short alternateSetting );
- static void CentronicsStatus( USBPB *usbprint, Ptr p, short interfaceNum );
- static void CompletionProc(USBPB *pb);
- static int cstrlen( char *p );
- static void cstrcpy( char *dst, char *src );
- static void cstrcat( char *dst, char *src );
-
- void PrinterDeviceInitiateTransaction(USBPB *pb);
-
- OSErr CFMInitialization( CFragInitBlock *initBlock );
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: HexString8
-
- Input Parameters:
- v unsigned long value
-
- Output Parameters:
- p 8 bytes: hex string representing value
-
- Description:
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- HexString8( unsigned long v, unsigned char *p )
- {
- int shift;
-
- for ( shift = 32-4; shift >= 0; shift -= 4 )
- {
- char c = (v >> shift) & 0x0F;
- *p++ = c + (c > 9? ('A'-10): '0');
- }
- }
-
- #if DEBUG
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: hexstr
-
- Input Parameters:
- count number of bytes
- p pointer to bytes
-
- Output Parameters:
- q hex dump of data
-
- Description:
-
- Change History:
- 28 Jul 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- hexstr( int count, char *p, char *q );
-
- void
- hexstr( int count, char *p, char *q )
- {
- char *s = p;
- int i = count;
- for ( ; count > 0; --count, ++p )
- {
- int hi, lo;
- hi = (*p >> 4)& 0x0F;
- lo = *p & 0x0F;
- *q++ = '0';
- *q++ = 'x';
- *q++ = hi + (hi > 9? 'A' - 10: '0');
- *q++ = lo + (lo > 9? 'A' - 10: '0');
- *q++ = ' ';
- }
- for ( ; i > 0; --i, ++s )
- *q++ = *s < ' ' || *s > 0x7E? '.': *s;
- }
- #endif
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: cstrlen
-
- Input Parameters:
- p pointer to c-string
-
- Output Parameters:
- int length of string
-
- Description:
- A replacement for strlen, since we don't want to depend on the
- c library (can cause vm double page faults)
-
- Change History:
- 17 Aug 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
- static int
- cstrlen( char *p )
- {
- int result = 0;
-
- while ( *p++ != '\0' )
- ++result;
-
- return result;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: cstrcpy
-
- Input Parameters:
- src pointer to source c-string
-
- Output Parameters:
- dst c-string copy of src string
-
- Description:
- A replacement for strcpy, since we don't want to depend on the
- c library (can cause vm double page faults)
-
- Change History:
- 17 Aug 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
- static void
- cstrcpy( char *dst, char *src )
- {
- while ( (*dst++ = *src++) != 0 )
- ;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: cstrcat
-
- Input Parameters:
- src pointer to source c-string
-
- Output Parameters:
- dst c-string copy of src string
-
- Description:
- A replacement for strcpy, since we don't want to depend on the
- c library (can cause vm double page faults)
-
- Change History:
- 17 Aug 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
- static void
- cstrcat( char *dst, char *src )
- {
- dst += cstrlen( dst ); // skip to end of the existing string
- while ( (*dst++ = *src++) != 0 )
- ;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: USBStatusStr
-
- Input Parameters:
- usbStatus usb error code
- kind kPString or kCString
-
- Output Parameters:
- unsigned char * description of error (c-string or p-string)
-
- Description:
- a simple mapping of errors to human-readable form
-
- Change History:
- 24 Apr 1998, oja: param to HexString8 was off-by-one
- 26 Mar 1998, oja: added kStrPrintClass to catenated strings
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static unsigned char *
- USBStatusStr( OSStatus usbStatus, int kind )
- {
- unsigned char *p;
-
- switch ( usbStatus )
- {
- case kUSBInternalErr: p = "\p" kStrPrinterClass "Internal error"; break;
- case kUSBUnknownDeviceErr: p = "\p" kStrPrinterClass "Unknown device"; break;
- case kUSBUnknownPipeErr: p = "\p" kStrPrinterClass "Unknown pipe"; break;
- case kUSBTooManyPipesErr: p = "\p" kStrPrinterClass "Too many pipes"; break;
- case kUSBIncorrectTypeErr: p = "\p" kStrPrinterClass "Incorrect type"; break;
- case kUSBRqErr: p = "\p" kStrPrinterClass "Request error"; break;
- case kUSBUnknownRequestErr: p = "\p" kStrPrinterClass "Unknown request"; break;
- case kUSBTooManyTransactionsErr: p = "\p" kStrPrinterClass "Too many transactions"; break;
- case kUSBAlreadyOpenErr: p = "\p" kStrPrinterClass "Already open"; break;
- case kUSBNoDeviceErr: p = "\p" kStrPrinterClass "No device"; break;
- case kUSBDeviceErr: p = "\p" kStrPrinterClass "Device error"; break;
- case kUSBOutOfMemoryErr: p = "\p" kStrPrinterClass "Out of memory"; break;
- case kUSBNotFound: p = "\p" kStrPrinterClass "Not found"; break;
- case kUSBLinkErr: p = "\p" kStrPrinterClass "Link Err"; break;
- case kUSBCRCErr: p = "\p" kStrPrinterClass "Comms/Device err, bad CRC"; break;
- case kUSBBitstufErr: p = "\p" kStrPrinterClass "Comms/Device err, bitstuffing"; break;
- case kUSBDataToggleErr: p = "\p" kStrPrinterClass "Comms/Device err, Bad data toggle"; break;
- case kUSBEndpointStallErr: p = "\p" kStrPrinterClass "Device didn't understand"; break;
- case kUSBNotRespondingErr: p = "\p" kStrPrinterClass "No device, device hung"; break;
- case kUSBPIDCheckErr: p = "\p" kStrPrinterClass "Comms/Device err, PID CRC error"; break;
- case kUSBWrongPIDErr: p = "\p" kStrPrinterClass "Comms/Device err, Bad or wrong PID"; break;
- case kUSBOverRunErr: p = "\p" kStrPrinterClass "Packet too large or more data than buffer"; break;
- case kUSBUnderRunErr: p = "\p" kStrPrinterClass "Less data than buffer"; break;
- case kUSBRes1Err: p = "\p" kStrPrinterClass "kUSBRes1Err"; break;
- case kUSBRes2Err: p = "\p" kStrPrinterClass "kUSBRes1Err"; break;
- case kUSBBufOvrRunErr: p = "\p" kStrPrinterClass "Buffer over run error"; break;
- case kUSBBufUnderRunErr: p = "\p" kStrPrinterClass "Buffer under run error"; break;
- case kUSBNotSent1Err: p = "\p" kStrPrinterClass "Transaction not sent1"; break;
- case kUSBNotSent2Err: p = "\p" kStrPrinterClass "Transaction not sent2"; break;
- default:
- p = "\p" kStrPrinterClass "Unknown error nnnnnnnn";
- HexString8( usbStatus, p + *p - 8 + 1 );
- break;
- }
-
- return kind == kPString? p: p + 1;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: StateStr
-
- Input Parameters:
- usbRefCon usb error code
- kind kPString or kCString
-
- Output Parameters:
- unsigned char * description of state (c-string or p-string)
-
- Description:
- a simple mapping of states to human-readable form
-
- Change History:
- 24 Apr 1998, oja: param to HexString8 was off-by-one
- 26 Mar 1998, oja: added kStrPrintClass to catenated strings
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static unsigned char *
- StateStr( OSStatus refCon, int kind )
- {
- unsigned char *p;
-
- refCon &= ~(kTransactionPending | kRetryTransaction | kReturnFromDriver);
- switch ( refCon )
- {
- case kGetCapabilityString: p = "\p" kStrPrinterClass "kGetCapabilityString"; break;
- case kDelayGetCapability: p = "\p" kStrPrinterClass "kDelayGetCapability"; break;
- case kFindBulkOutPipe: p = "\p" kStrPrinterClass "kFindBulkOutPipe"; break;
- case kFindBulkInPipe: p = "\p" kStrPrinterClass "kFindBulkInPipe"; break;
- case kTaskTimeRequired: p = "\p" kStrPrinterClass "kTaskTimeRequired"; break;
- default:
- p = "\p" kStrPrinterClass "Unknown state nnnnnnnn";
- HexString8( refCon, p + *p - 8 + 1 );
- break;
- }
- return kind == kPString? p: p + 1;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: HiHex
-
- Input Parameters:
- v only low byte used
-
- Output Parameters:
- <function result> high nibble represented as ASCII char
-
- Description:
-
- Change History:
- 20 Mar 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static unsigned char
- HiHex( int v )
- {
- unsigned char hinibble = (v >> 4) & 0x0f;
- return hinibble + ((hinibble > 9)? ('A'-10): '0');
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: LoHex
-
- Input Parameters:
- v only low byte used
-
- Output Parameters:
- <function result> low nibble represented as ASCII char
-
- Description:
-
- Change History:
- 20 Mar 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static unsigned char
- LoHex( int v )
- {
- unsigned char lonibble = v & 0x0f;
- return lonibble + ((lonibble > 9)? ('A'-10): '0');
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: immediateError
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static Boolean
- immediateError(OSStatus err)
- {
- return((err != kUSBPending) && (err != noErr) );
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: SetNullUSBParamBlock
-
- Input Parameters:
- pb pointer to USB parameter block
- dev USB device reference
- Output Parameters:
- pb all fields set to default values
-
- Description:
- setup a USB parameter block for use by the current device
-
- Change History:
- 8 Jun 1998, oja: modified for new param blocks
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb )
- {
- pb->qlink = NULL;
- pb->qType = 0;
- pb->pbLength = sizeof(USBPB);
- pb->pbVersion = kUSBCurrentPBVersion;
- pb->usbFlags = 0;
- pb->usbStatus = noErr;
- pb->usbCompletion = (USBCompletion) NULL;
-
- pb->usbReference = dev;
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: ParseCapability
-
- Input Parameters:
- capability pointer to 1284-1994 capability string
- attribute pointer to c-string key we're retrieving (terminate with colon)
- *result_length maximum length of the result
-
- Output Parameters:
- result c-string which followed the key and was terminated by semi-colon
- (semi-colon has been stripped)
- *result_length actual length of the result (may be zero)
-
- Description:
- Search for "attribute" in the 1284 "capability" string
- The identifier is terminated with a semi-colon
-
- Return the attribute in result
- null-string if attribute not found.
-
- Change History:
- 20 Jul 1998, oja: fix computation of target_length
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- ParseCapability(
- unsigned char *capability,
- unsigned char *attribute,
- unsigned char *result,
- int *result_length
- )
- {
- //
- // search for "attribute" in the 1284 "capability" string
- //
- // the identifier is terminated with a semi-colon
- //
- // return the attribute in result
- // null-string if attribute not found
- //
- // <to do> skip blanks, isolate colon, skip blanks
- //
- int source_length,
- target_length;
- unsigned char *source,
- *target,
- *destination;
- //
- // begin a brute force search
- //
- source = attribute;
- source_length = cstrlen((char *)attribute );
-
- target = capability + 2; // skip the length
- target_length = capability[1] | (capability[0] << 8);
- target_length -= 2; // don't count the length
- while ( target_length >= source_length )
- {
- if ( memcmp( source, target, source_length ) == 0 )
- break;
- --target_length;
- ++target;
- }
-
- destination = result;
- *destination = 0; // empty result
-
- target += source_length;
- target_length -= source_length; // skip the attribute string
-
- if ( target_length > 0 )
- {
- //
- // we found the attribute in the capability string
- //
- while ( destination - result < *result_length ) // arbitrarily limit reply
- {
- if ( *target == ';' )
- break;
- *destination++ = *target++; // copy a byte of attribute over
- }
- *destination++ = '\0'; // trailing NUL
- *result_length = destination - result; // report the length of the data (with trailing NUL)
- }
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetClass
-
- Input Parameters:
- capability pointer to 1284-1994 capability string
- *result_length maximum length of the result
-
- Output Parameters:
- result c-string extracted from the MODEL key
- *result_length actual length of the result (may be zero)
-
- Description:
- CLASS is a Microsoft extension to the 1284-capability string
- if we don't find it
- we assume that the device is a printer
- Since the USB hardware has already indicated this, we're really allowing
- devices which aren't printers to be reached via the DRVRs we've installed.
-
- Change History:
- 26 Mar 1998, oja: result_length is output too
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetClass(
- unsigned char *capability,
- unsigned char *result,
- int *result_length
- )
- {
- UInt32 i;
- //
- // We supply the upper-case PRINTER to be consistent with 1284-1994
- // if we don't find a class.
- //
- ParseCapability( capability, (unsigned char *) "CLASS:", result, result_length);
- if ( *result == '\0' )
- ParseCapability( capability, (unsigned char *) "CLS:", result, result_length);
- if ( *result == '\0' )
- cstrcpy( (char *)result, "PRINTER" );
- while (result[i])
- {
- result[i] &= 0x7f;
- if (result[i] > 0x6f)
- result[i] -= (unsigned char)('a' - 'A');
- i++;
- }
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetModel
-
- Input Parameters:
- capability pointer to 1284-1994 capability string
- *result_length maximum length of the result
-
- Output Parameters:
- result c-string extracted from the MODEL key
- *result_length actual length of the result (may be zero)
-
- Description:
- MODEL is a required field of the 1284-capability string
- MODEL may be abbreviated MDL
-
- Change History:
- 26 Mar 1998, oja: result_length is output too
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetModel(
- unsigned char *capability,
- unsigned char *result,
- int *result_length
- )
- {
- //
- // Most manufacturers abbreviate, so we search for MDL first
- //
- ParseCapability( capability, (unsigned char *) "MDL:", result, result_length );
- if ( *result == '\0' )
- ParseCapability( capability, (unsigned char *) "MODEL:", result, result_length );
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetCommandSet
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
-
- Change History:
- 11 Nov 1998, oja: look for COMMAND SET not COMMAND-SET
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetCommandSet(
- unsigned char *capability,
- unsigned char *result,
- int *result_length
- )
- {
- //
- // COMMAND-SET is a required field of the 1284-capability string
- // COMMAND-SET may be abbreviated CMD
- //
- ParseCapability( capability, (unsigned char *) "CMD:", result, result_length );
- if ( *result == '\0' )
- ParseCapability( capability, (unsigned char *) "COMMAND SET:", result, result_length );
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetManufacturer
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
-
- Change History:
- 26 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetManufacturer(
- unsigned char *capability,
- unsigned char *result,
- int *result_length
- )
- {
- //
- // MANUFACTURER is a required field of the 1284-capability string
- // MANUFACTURER may be abbreviated MFG
- //
- ParseCapability( capability, (unsigned char *) "MFG:", result, result_length );
- if ( *result == '\0' )
- ParseCapability( capability, (unsigned char *) "MANUFACTURER:", result, result_length );
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: DeregisterDevice
-
- Input Parameters:
- pPrinterPB
-
- Output Parameters:
- <none>
-
- Description:
- remove the device from the name registry
-
- Change History:
- 11 Jun 1998, oja: test from RegistryCStrEntryLookup was wrong direction
- 17 Apr 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static OSStatus
- DeregisterDevice( struct usbPrinterPBStruct *pPrinterPB )
- {
- OSStatus err;
- RegEntryID self;
-
- RegistryEntryIDInit( &self );
- err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
- if ( err == noErr )
- {
- err = RegistryEntryDelete( &self);
- }
- RegistryEntryIDDispose(&self);
- if (err == noErr && pPrinterPB->outRefNum != -1 )
- err = TradRemoveDriver( pPrinterPB->outRefNum, false );
- if (err == noErr && pPrinterPB->inRefNum != -1 )
- err = TradRemoveDriver( pPrinterPB->inRefNum, false );
-
- return err;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: RegisterDevice
-
- Input Parameters:
- pPrinterPB
-
- Output Parameters:
- <none>
-
- Description:
- add the device into the name registry; we can't insert just the node
- if the parent nodes aren't present.
-
- if it isn't present
- insert the device CLASS into the registry
- if it isn't present
- insert the device MODEL into the registry
- finally insert the device itself into the registry
- we're careful to rename multiple devices
-
- Change History:
- 16 Nov 1998, oja: better support for attributes which aren't in string
- 16 Jul 1998, oja: fix params to sprintf
- 8 Jun 1998, oja: don't use register param (CW build)
- 26 Mar 1998, oja: only register significant part of drvrNames
- log null model name to Expert
- register command set
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static OSStatus
- RegisterDevice( struct usbPrinterPBStruct *pPrinterPB )
- {
- //
- // add the device into the name registry
- // if it isn't present
- // insert the device CLASS into the registry
- // if it isn't present
- // insert the device MODEL into the registry
- // finally insert the device itself into the registry
- // we're careful to rename multiple devices
- //
- Str255 identification,
- devclass,
- model,
- commands,
- tempstr;
- RegEntryID parent, where, self;
- OSStatus err;
- int model_length,
- command_length,
- class_length;
-
- class_length = sizeof(devclass);
- GetClass( pPrinterPB->pCapabilityString, devclass, &class_length );
-
- command_length = sizeof(commands);
- GetCommandSet(pPrinterPB->pCapabilityString, commands, &command_length );
-
- cstrcpy( (char *)pPrinterPB->name, (char *)"Devices:device-tree:" );
- cstrcat( (char *)pPrinterPB->name, (char *)devclass );
-
- RegistryEntryIDInit( &where );
- err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name, &where );
- if ( err == nrPathNotFound )
- {
- // class not in registry
- // create a node for all devices of this CLASS
- //
- RegistryEntryIDInit( &parent );
- err = RegistryCStrEntryLookup( nil, "Devices:device-tree:" , &parent );
- if ( err == noErr )
- err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &where );
- RegistryEntryIDDispose(&parent);
-
- }
- //
- // add this model into the name registry of this class
- //
- if ( err == noErr )
- {
- model_length = sizeof(model);
- GetModel( pPrinterPB->pCapabilityString, model, &model_length );
- if ( *model != '\0' )
- {
- cstrcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
- cstrcat( (char *)pPrinterPB->name, (char *)devclass );
- cstrcat( (char *)pPrinterPB->name, ":" );
- cstrcat( (char *)pPrinterPB->name, (char *)model );
- RegistryEntryIDInit( &self );
- err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
- if ( err != noErr )
- {
- // model not in registry
- err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
- }
- RegistryEntryIDDispose(&self);
- }
- }
- //
- // add this instance of this model of this class
- // into the name registry
- //
- if ( *model == '\0' )
- {
- //
- // possibly the cable isn't firmly connected or the printer isn't switched on
- //
- err = kUSBInternalErr;
- USBExpertFatalError(pPrinterPB->deviceRef, err, "\p"kStrPrinterClass "\pModel undefined", 0);
- }
- if ( err == noErr )
- {
- //
- // start off by identifying the device simply by the model name
- // increment the numeric suffix until we successfully registry the device
- //
- Str32 suffix;
- int numeric_suffix;
-
- cstrcpy( (char *)identification, (char *)model );
- RegistryEntryIDInit( &self );
- for ( numeric_suffix = 1; numeric_suffix < MAX_SUFFIX; ++numeric_suffix )
- {
- cstrcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
- cstrcat( (char *)pPrinterPB->name, (char *)devclass );
- cstrcat( (char *)pPrinterPB->name, ":" );
- cstrcat( (char *)pPrinterPB->name, (char *)model );
- cstrcat( (char *)pPrinterPB->name, ":" );
- cstrcat( (char *)pPrinterPB->name, (char *)identification );
- err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
- if ( err != noErr )
- {
- // enter device in registry
- err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "drvrOut", &pPrinterPB->driverOutName, 1 + pPrinterPB->driverOutName[0] );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "outRef", &pPrinterPB->outRefNum, sizeof(pPrinterPB->outRefNum) );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "drvrIn", &pPrinterPB->driverInName, 1 + pPrinterPB->driverInName[0] );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "inRef", &pPrinterPB->inRefNum, sizeof(pPrinterPB->inRefNum) );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "privateData", &pPrinterPB, sizeof(pPrinterPB) );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "read", &pPrinterPB->r, sizeof(QueueUSBReadUPP) );
- if ( err == noErr )
- err = RegistryPropertyCreate( &self, "write", &pPrinterPB->w, sizeof(QueueUSBWriteUPP) );
- if ( err == noErr && *commands != '\0' )
- err = RegistryPropertyCreate( &self, "command-set", &commands, command_length );
- break;
- }
- //
- // if this name didn't succeed
- // try the next numeric suffix
- //
- sprintf( (char *)suffix, " %d", numeric_suffix );
- cstrcpy( (char *)identification, (char *)model );
- cstrcat( (char *)identification, (char *)suffix );
- }
- RegistryEntryIDDispose(&self);
- }
-
- CStrToPStr((unsigned char *)tempstr, (char const *)pPrinterPB->name );
-
- USBExpertStatus( pPrinterPB->deviceRef, "\p" kStrPrinterClass "Added printer to name registry", 0 );
- USBExpertStatus( pPrinterPB->deviceRef, tempstr, err );
- RegistryEntryIDDispose(&where);
-
- LOGGING( logfile = fopen( "USBPrinter.log", "wb+" ) );
- return err;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: LoadResources
-
- Input Parameters:
- pPrinterPB pointer to class driver's private storage
-
- Output Parameters:
- OSStatus resource load error
-
- Description:
- Initialize time is the only safe time to to load resources from our file.
- Here's where we load resources and detach them from the resource manager.
- Later we'll use these private copies instead of GetResource calls.
-
- Using the file spec that we got from the CFMInitialization routine, open
- our resource fork.
-
- Change History:
- 11 Jun 1998, oja: removed hardcoded filename, use printerClassDriverFileSpec
- 20 Mar 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static OSStatus
- LoadResources( struct usbPrinterPBStruct *pPrinterPB )
- {
- short rf = -1; // class driver resource fork
- OSStatus err;
-
- //
- // open the resource fork of this class driver
- //
- rf = FSpOpenResFile( &printerClassDriverFileSpec,fsRdPerm );
- err = ResError();
-
- //
- // load the DRVR that we'll stick in the unit table
- //
- pPrinterPB->hDrvr = NULL;
- if ( err == noErr )
- {
- pPrinterPB->hDrvr = (DRVRHeaderHandle) Get1Resource( 'DRVR', kUSBParallelDrvrRsrcID );
- if ( pPrinterPB->hDrvr != NULL )
- DetachResource( (Handle) pPrinterPB->hDrvr );
- err = ResError();
- }
-
- if ( rf != -1 )
- CloseResFile( rf );
-
- return err;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: InstallDrivers
-
- Input Parameters:
- pPrinterPB
-
- Output Parameters:
- OSStatus error code
-
- Description:
- install read and write drivers in the unit table
- we have separate drivers so that we can support a full-duplex protocol
- rename the driver we just installed (so multiple copies don't conflict)
- We use the DRVR -refnum-1 so that the driver name has the same hex chars
- as the driver number (for manual verification in MacsBug)
-
- Change History:
- 13 Jul 1998, oja: init err to noErr
- 26 Mar 1998, oja: Use refnum -1, use infix location to enumerate
- DRVR
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static OSStatus
- InstallDrivers( struct usbPrinterPBStruct *pPrinterPB )
- {
- //
- // install the driver in the unit table
- // rename the driver we just installed (so multiple copies don't conflict)
- //
- short refNum; // DRVR refNum
- OSStatus err = paramErr; // couldn't find driver
-
- if ( pPrinterPB->hDrvr != NULL )
- err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->outRefNum );
-
- if ( err == noErr )
- {
- UnitNumber unit;
- DriverFlags flags;
- DRVRHeaderPtr hdr;
- unsigned char *suffix, // append "In" and "Out"
- *infix; // driver reference number follows the ".USB"
-
- TradGetDriverInformation( pPrinterPB->outRefNum, &unit, &flags, pPrinterPB->driverOutName, &hdr );
- BlockMove( pPrinterPB->driverOutName, pPrinterPB->driverInName, 1 + pPrinterPB->driverOutName[0] );
-
- suffix = pPrinterPB->driverOutName + pPrinterPB->driverOutName[0] - 2;
- infix = pPrinterPB->driverOutName + kDrvrFirstDigit;
- infix[0] = HiHex( -pPrinterPB->outRefNum -1 );
- infix[1] = LoHex( -pPrinterPB->outRefNum -1 );
- suffix[0] = 'O';
- suffix[1] = 'u';
- suffix[2] = 't';
- TradRenameDriver( pPrinterPB->outRefNum, pPrinterPB->driverOutName );
- //
- // set the driver data to point to our parameter block
- //
- err = OpenDriver( pPrinterPB->driverOutName, &refNum );
- if ( err == noErr )
- {
- struct usbPrinterPBStruct *param = pPrinterPB;
- err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
- CloseDriver( refNum );
- }
- err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->inRefNum );
- if ( err == noErr )
- {
-
- suffix = pPrinterPB->driverInName + pPrinterPB->driverInName[0] - 1;
- infix = pPrinterPB->driverInName + kDrvrFirstDigit;
- infix[0] = HiHex( -pPrinterPB->inRefNum -1 );
- infix[1] = LoHex( -pPrinterPB->inRefNum -1 );
- suffix[0] = 'I';
- suffix[1] = 'n';
- TradRenameDriver( pPrinterPB->inRefNum, pPrinterPB->driverInName );
- //
- // set the driver data to point to our parameter block
- //
- err = OpenDriver( pPrinterPB->driverInName, &refNum );
- if ( err == noErr )
- {
- struct usbPrinterPBStruct *param = pPrinterPB;
- err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
- CloseDriver( refNum );
- }
- }
- }
-
- return err;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetCapability
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
- Asynchronous completion.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetCapability( struct usbPrinterPBStruct *pPrinterPB, unsigned char *p, int length )
- {
- //
- // queue a transaction to retrieve the 1284 capability string
- // we must have assigned the interface by this point since the capability string
- // may vary with the interface
- //
- OSStatus err;
- USBPB *pb = &pPrinterPB->pb;
-
- SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
-
- pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
- pb->usbBuffer = 0;
- pb->usbActCount = 0;
- pb->usbReqCount = 0;
-
- pb->usb.cntl.BRequest = kUSBPrintClassGetDeviceID;
- pb->usb.cntl.WValue = pPrinterPB->configurationNumber; // configuration
- pb->usb.cntl.WIndex = (pPrinterPB->interfaceNumber<<8) | pPrinterPB->alternateSetting;
-
- pb->usbReqCount = length;
- pb->usbBuffer = p;
-
- pb->usbRefcon |= kTransactionPending;
- pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- err = USBDeviceRequest(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetCapability", 0);
- pb->usbRefcon |= kReturnFromDriver;
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: IsLucentCable
-
- Input Parameters:
- dev USB device descriptor
-
- Output Parameters:
- Return 1 if the USB device is a USB-parallel cable
-
- Description:
-
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static int
- IsLucentCable( USBDeviceDescriptor *dev )
- {
- return ( USBToHostWord(dev->vendor) == 0x47E && USBToHostWord(dev->product) == 0x1001 )? 1: 0;
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: GetInterface
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
- Asynchronous completion.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- GetInterface( USBPB *pb, UInt8 *alt )
- {
- //
- // make sure we account for any alternate interface currently in use by the device
- //
- OSStatus err;
-
- pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBInterface);
-
- pb->usb.cntl.BRequest = kUSBRqGetInterface;
- pb->usb.cntl.WValue = 0;
- pb->usb.cntl.WIndex = 0;
-
- pb->usbReqCount = sizeof(UInt8); // single byte is requested
- pb->usbBuffer = alt;
-
- pb->usbStatus = 0;
- pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- pb->usbRefcon |= kTransactionPending;
-
- err = USBDeviceRequest(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetInterface", 0);
- pb->usbRefcon |= kReturnFromDriver;
- }
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: ReadCompletion
-
- Input Parameters:
- pb USB parameter block
-
- Output Parameters:
- <none>
-
- Description:
- USB read requests complete here.
- We dequeue the MacOS DRVR read requests
-
- Change History:
- 10 Aug 1998, oja: set readDrvr.ctl to NULL when finished
- 28 Jul 1998, oja: breakdown transactions into MAX_USB_TRANSFER_SIZE
- 27 Jul 1998, oja: lock memory (UIM doesn't do this properly)
- 20 Jul 1998, oja: retry transactions
- 8 Jun 1998, oja: clear stalls on error
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- ReadCompletion(USBPB *pb)
- {
- // call the user completion routine
- struct usbPrinterPBStruct
- *pPrinterPB = (struct usbPrinterPBStruct *) pb->usbRefcon;
- IOParamPtr clientParam = pPrinterPB->readDrvr.pb;
- OSStatus err = pb->usbStatus;
- DCtlPtr ctlLocal;
-
- #if MACSBUG_ON_READ_COMPLETE
- Str255 text;
- sprintf( (char *)text, " PrinterClass Read Complete(%d): %d", pb->usbStatus, pb->usbActCount );
- text[0] = cstrlen((char *)text); // c2pstr
- DebugStr( text );
- #endif
-
- #if DOUBLE_BUFFER
- //
- // copy the user data from our page aligned buffer
- //
- USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "ReadCompletion - read " , (UInt32)pb->usbActCount );
-
- if ( pb->usbActCount > 0 )
- BlockCopy( pPrinterPB->pageReadAlignedBuffer, clientParam->ioBuffer + clientParam->ioActCount, pb->usbActCount );
- #endif
- // update the amount of data actually transferred
- clientParam->ioActCount += pb->usbActCount;
-
- switch( pb->usbStatus )
- {
- //
- // only retry low level hardware problems
- // note: abort transactions will end up here as well
- //
- case kUSBLinkErr:
- case kUSBCRCErr: /* Pipe stall, bad CRC */
- case kUSBBitstufErr: /* Pipe stall, bitstuffing */
- case kUSBDataToggleErr: /* Pipe stall, Bad data toggle */
- case kUSBNotRespondingErr: /* Pipe stall, No device, device hung */
- case kUSBPIDCheckErr: /* Pipe stall, PID CRC error */
- case kUSBWrongPIDErr: /* Pipe stall, Bad or wrong PID */
- if ( --(pPrinterPB->readRetryCount) > 0 )
- {
- // we got an error, and we still want to retry, clear any stalls
- USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "ReadCompletion retry" , pb->usbStatus );
- USBClearPipeStallByReference(pPrinterPB->readPipeRef);
- pb->usbStatus = noErr;
- }
- break;
- case kUSBAbortedError: /* user cancel, or hot unplug */
- USBClearPipeStallByReference(pPrinterPB->readPipeRef);
- USBClearPipeStallByReference(pPrinterPB->deviceRef);
- break;
- //
- // any other error will be reported to the client
- //
- default:
- case noErr:
- break;
- }
- if ( pb->usbStatus == noErr && // there were no problems
- pb->usbActCount >= pb->usbReqCount && // we got all the data we requested
- clientParam->ioActCount < clientParam->ioReqCount ) // we still want more data
- {
- //
- // haven't finish the client's request
- // update the pointers and start another bulk read transaction
- //
- #if LOCK_MEMORY
- err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
- IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion UnlockMem failed" ) );
- #endif
- pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
- pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
- #if MAX_USB_TRANSFER_SIZE
- if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
- pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
- #endif
- #if DOUBLE_BUFFER
- //
- // make sure we have enough room in our buffer
- //
- if ( pb->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
- pb->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
- pb->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
- #endif
- #if LOCK_MEMORY
- err = LockMemory( pb->usbBuffer, pb->usbReqCount );
- IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion LockMem failed" ) );
- if ( err == noErr )
- #endif
- err = USBBulkRead( pb );
- if ( immediateError(err) )
- {
- USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "ReadCompletion finish immed err" , err );
-
- pb->usbCompletion = (USBCompletion) NULL; // checked by Finalize
- if ( pPrinterPB->readDrvr.ctl != NULL )
- {
- ctlLocal = pPrinterPB->readDrvr.ctl;
- pPrinterPB->readDrvr.ctl = NULL;
- CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, ctlLocal );
- }
- }
- }
- else
- {
- //
- // either we have an error which we're not retrying
- // or we successfully completed
- //
- #if LOCK_MEMORY
- err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
- IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion concluded UnlockMem failed" ) );
- #endif
- IF_DEBUG( if (pb->usbStatus != noErr) USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "ReadCompletion Error" , pb->usbStatus ) );
- pb->usbCompletion = (USBCompletion) NULL; // checked by Finalize
- USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "readDrvr.ctl = " , (UInt32)pPrinterPB->readDrvr.ctl );
- if ( pPrinterPB->readDrvr.ctl != NULL )
- {
- ctlLocal = pPrinterPB->readDrvr.ctl;
- pPrinterPB->readDrvr.ctl = NULL;
- CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, ctlLocal);
- }
- else
- {
- IF_DEBUG( DebugStr( "\pReadCompletion() pPrinterPB->readDrvr.ctl == NULL" ) );
- }
- }
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: WriteCompletion
-
- Input Parameters:
- pb USB parameter block
-
- Output Parameters:
- <none>
-
- Description:
- USB write requests complete here.
- We dequeue the MacOS DRVR write requests
-
- when breaking up transactions we use ioActCount to determine how much remains
- of the original request and where the next request begins
- if we've failed with a USB error
- usbActCount indicates how much data has been transferred with the current request
- and if the retry count hasn't been exceeded
- we proceed as if we'd just requested that much in this transactions
- note the retry count is cumulative for the original client request
- not for each usb transaction
-
- Change History:
- 16 Nov 1998, oja: restored missing writeDrvr.ctl != NULL
- 4 Nov 1998, oja: allow chaining of DRVR calls
- 10 Aug 1998, oja: set writeDrvr.ctl to NULL when finished
- 28 Jul 1998, oja: breakdown transactions into MAX_USB_TRANSFER_SIZE
- 27 Jul 1998, oja: lock memory (UIM doesn't do this properly)
- 20 Jul 1998, oja: retry transactions
- 16 Jul 1998, oja: clear write pipe, not control pipe
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- WriteCompletion(USBPB *pb)
- {
- // call the user completion routine
- struct usbPrinterPBStruct
- *pPrinterPB = (struct usbPrinterPBStruct *) pb->usbRefcon;
- IOParamPtr clientParam = pPrinterPB->writeDrvr.pb;
- DCtlPtr ctlLocal;
- OSStatus err = pb->usbStatus;
-
- #if MACSBUG_ON_WRITE_COMPLETE
- Str255 text;
- sprintf( (char *)text, " PrinterClass Write Complete(%d): %d", pb->usbStatus, pb->usbActCount );
- text[0] = cstrlen((char *)text); // c2pstr
- DebugStr( text );
- #endif
-
- // update the amount of data actually transferred
- clientParam->ioActCount += pb->usbActCount;
- USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "WriteCompletion - wrote " , (UInt32)pb->usbActCount );
-
- switch( pb->usbStatus )
- {
- //
- // only retry low level hardware problems
- // note: abort transactions will end up here as well
- //
- case kUSBLinkErr:
- case kUSBCRCErr: /* Pipe stall, bad CRC */
- case kUSBBitstufErr: /* Pipe stall, bitstuffing */
- case kUSBDataToggleErr: /* Pipe stall, Bad data toggle */
- case kUSBNotRespondingErr: /* Pipe stall, No device, device hung */
- case kUSBPIDCheckErr: /* Pipe stall, PID CRC error */
- case kUSBWrongPIDErr: /* Pipe stall, Bad or wrong PID */
- if ( --(pPrinterPB->writeRetryCount) > 0 )
- {
- // we got an error, and we still want to retry, clear any stalls
- USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "WriteCompletion retry" , pb->usbStatus );
- USBClearPipeStallByReference(pPrinterPB->writePipeRef);
- pb->usbStatus = noErr;
- }
- break;
- case kUSBAbortedError: /* user cancel, or hot unplug */
- USBClearPipeStallByReference(pPrinterPB->writePipeRef);
- USBClearPipeStallByReference(pPrinterPB->deviceRef);
- break;
- //
- // any other error will be reported to the client
- //
- default:
- case noErr:
- break;
- }
-
- if ( pb->usbStatus == noErr && clientParam->ioActCount < clientParam->ioReqCount )
- {
- //
- // haven't finish the client's request
- // update the pointers and start another bulkOut transaction
- //
- #if LOCK_MEMORY
- err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
- IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion UnlockMem failed" ) );
- #endif
- pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
- pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
- #if MAX_USB_TRANSFER_SIZE
- if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
- pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
- #endif
- #if DOUBLE_BUFFER
- //
- // make sure we have enough room in our buffer
- // then copy the user data into our page aligned buffer
- //
- if ( pb->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
- pb->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
- BlockCopy( pb->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, pb->usbReqCount );
- pb->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
- #endif
- #if LOCK_MEMORY
- err = LockMemory( pb->usbBuffer, pb->usbReqCount );
- IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion LockMem failed" ) );
- if ( err == noErr )
- #endif
- err = USBBulkWrite( pb );
- if ( immediateError(err) )
- {
- USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "WriteCompletion finish immed err" , err );
-
- pb->usbCompletion = (USBCompletion) NULL; // checked by Finalize
- if ( pPrinterPB->writeDrvr.ctl != NULL )
- {
- ctlLocal = pPrinterPB->writeDrvr.ctl;
- pPrinterPB->writeDrvr.ctl = NULL;
- CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, ctlLocal );
- }
- }
- }
- else
- {
- //
- // either we have an error which we're not retrying
- // or we successfully completed
- //
- #if LOCK_MEMORY
- err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
- IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion concluded UnlockMem failed" ) );
- #endif
- IF_DEBUG( if (pb->usbStatus != noErr) USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "WriteCompletion Error" , pb->usbStatus ) );
- pb->usbCompletion = (USBCompletion) NULL; // checked by Finalize
- USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "writeDrvr.ctl = " , (UInt32)pPrinterPB->writeDrvr.ctl );
- if ( pPrinterPB->writeDrvr.ctl != NULL )
- {
- ctlLocal = pPrinterPB->writeDrvr.ctl;
- pPrinterPB->writeDrvr.ctl = NULL;
- CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, ctlLocal );
- }
- else
- {
- IF_DEBUG( DebugStr( "\pWriteCompletion() pPrinterPB->writeDrvr.ctl == NULL" ) );
- }
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: QueueRead
-
- Input Parameters:
- pb MacOS device manager parameter block
- ctl device manager dCtl block
- pPrinterPB current printing device class's storage
-
- Output Parameters:
- <none>
-
- Description:
- MacOS DRVR read requests are re-queued here to the USB
- Since we only allow one read request pending at a time, we're able
- to use the USB refCon to point to our class driver's storage.
-
- Change History:
- 16 Nov 1998, oja: added LOCKMEMORY
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- QueueRead( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
- {
- OSStatus err;
- USBPB *usbprint = &pPrinterPB->in;
-
- #if MACSBUG_ON_READ
- Str255 text;
-
- sprintf( (char *)text, " PrinterClass Read: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
- text[0] = cstrlen((char *)text); // c2pstr
- USBExpertStatus(usbprint->usbReference, text, usbprint->usbStatus );
- // DebugStr( text );
- #endif
-
- pb->ioActCount = 0; // nothing transfered yet
- if ( pPrinterPB->terminating )
- pb->ioResult = abortErr;
- else
- {
-
- pPrinterPB->readRetryCount = 5;
- pPrinterPB->readDrvr.pb= pb;
- pPrinterPB->readDrvr.ctl = ctl;
- if (( pPrinterPB->readPipeRef != NULL ) && (pPrinterPB->printerConfigured))
- {
- SetNullUSBParamBlock( pPrinterPB->readPipeRef, usbprint );
- USBExpertStatus(usbprint->usbReference, "\pSet up to do bulk read", pb->ioReqCount );
- usbprint->usbActCount = 0;
- usbprint->usbBuffer = pb->ioBuffer;
- usbprint->usbReqCount = pb->ioReqCount;
-
- #if MAX_USB_TRANSFER_SIZE
- //
- // the completion routine will queue another BulkWrite until we exhaust the data
- // or there is an error which can't be retried
- //
- if ( usbprint->usbReqCount > MAX_USB_TRANSFER_SIZE )
- usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
- #endif
- #if DOUBLE_BUFFER
- //
- // make sure we have enough room in our buffer
- // then copy the user data into our page aligned buffer
- //
- if ( usbprint->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
- usbprint->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
- usbprint->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
- #endif
- usbprint->usbRefcon = (unsigned long) pPrinterPB;
- usbprint->usbCompletion = (USBCompletion) ReadCompletion;
-
- pb->ioResult = ioInProgress;
- #if LOCK_MEMORY
- err = LockMemory( usbprint->usbBuffer, usbprint->usbReqCount );
- IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass QueueRead LockMem failed" ) );
- if ( err == noErr )
- #endif
- err = USBBulkRead( usbprint );
- if ( immediateError(err) )
- {
- USBExpertStatus(usbprint->usbReference, "\pError doing bulk read",0 );
- IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
- pb->ioResult = err;
- }
- }
- else
- {
- USBExpertStatus(usbprint->usbReference, "\p" kStrPrinterClass "Read to unopened pipe" , usbprint->usbStatus ) ;
- pb->ioResult = abortErr;
- }
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: QueueWrite
-
- Input Parameters:
- pb MacOS device manager parameter block
- ctl device manager dCtl block
- pPrinterPB current printing device class's storage
-
- Output Parameters:
- <none>
-
- Description:
- MacOS DRVR write requests are re-queued here to the USB
- Since we only allow one read request pending at a time, we're able
- to use the USB refCon to point to our class driver's storage.
-
- Change History:
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- QueueWrite( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
- {
- OSStatus err;
- USBPB *usbprint = &pPrinterPB->out;
- #if VIRTUAL_MEMORY_CHECK
- //
- // dump the VM table
- //
- Str255 text;
- LogicalToPhysicalTable *vmTable;
- MemoryBlock *physical;
- unsigned long vmCount,
- vmEntry,
- vmTblLength;
- #endif
-
- #if MACSBUG_ON_WRITE
- Str255 text;
- sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
- text[0] = cstrlen((char *)text); // c2pstr
- USBExpertStatus(usbprint->usbReference, text, usbprint->usbStatus );
- // DebugStr( text );
- #endif
-
- #if VIRTUAL_MEMORY_CHECK
- //
- // this check current won't compile without runtime error: need to lock memory, but lock has moved
- //
- sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
- text[0] = cstrlen((char *)text); // c2pstr
- USBExpertStatus(usbprint->usbReference, text, usbprint->usbStatus );
-
- vmCount = 127;
- vmTblLength = (vmCount+1)*sizeof(MemoryBlock);
- vmTable = (LogicalToPhysicalTable *) NewPtrSys( vmTblLength );
- LockMemory( vmTable, vmTblLength );
- LockMemory( &vmCount, sizeof(unsigned long) );
- vmTable->logical.address = pb->ioBuffer;
- vmTable->logical.count = pb->ioReqCount;
- err = GetPhysical( vmTable, &vmCount );
-
- if ( err == noErr )
- {
- for ( vmEntry = 0, physical = &vmTable->physical[0]; vmEntry < vmCount; ++vmEntry , ++physical)
- {
- sprintf( (char *)text, " PrinterClass Write: VM @%08x (%d)", physical->address, physical->count );
- text[0] = cstrlen((char *)text); // c2pstr
- USBExpertStatus(usbprint->usbReference, text, usbprint->usbStatus );
- }
- }
- UnlockMemory( vmTable, vmTblLength );
- UnlockMemory( &vmCount, sizeof(unsigned long) );
- #endif
- pb->ioActCount = 0; // nothing transfered yet
-
-
- usbprint->usbStatus = noErr; // forget about abort and things from previous writes
- if ( pPrinterPB->terminating )
- pb->ioResult = abortErr;
- else
- {
- pPrinterPB->writeRetryCount = 5;
- pPrinterPB->writeDrvr.pb = pb;
- pPrinterPB->writeDrvr.ctl = ctl;
- if (( pPrinterPB->writePipeRef != NULL ) && (pPrinterPB->printerConfigured))
- {
- SetNullUSBParamBlock( pPrinterPB->writePipeRef, usbprint );
- USBExpertStatus(usbprint->usbReference, "\pSet up to do bulk write", pb->ioReqCount );
- usbprint->usbActCount = 0;
- usbprint->usbBuffer = pb->ioBuffer;
- usbprint->usbReqCount = pb->ioReqCount;
- #if MAX_USB_TRANSFER_SIZE
- //
- // the completion routine will queue another BulkWrite until we exhaust the data
- // or there is an error which can't be retried
- //
- if ( usbprint->usbReqCount > MAX_USB_TRANSFER_SIZE )
- usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
- #endif
- #if DOUBLE_BUFFER
- //
- // make sure we have enough room in our buffer
- // then copy the user data into our page aligned buffer
- //
- if ( usbprint->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
- usbprint->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
- BlockCopy( usbprint->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, usbprint->usbReqCount );
- usbprint->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
- #endif
- usbprint->usbRefcon = (unsigned long) pPrinterPB;
- usbprint->usbCompletion = (USBCompletion) WriteCompletion;
-
- pb->ioResult = ioInProgress;
-
- #if LOCK_MEMORY
- err = LockMemory( usbprint->usbBuffer, usbprint->usbReqCount );
- IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass QueueWrite LockMem failed" ) );
- if ( err == noErr )
- #endif
- err = USBBulkWrite( usbprint );
- if ( immediateError(err) )
- {
- USBExpertStatus(usbprint->usbReference, "\pError doing bulk write",0 );
- IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
- pb->ioResult = err;
- }
- //
- // note our logging is one write for each the client request
- // not one write for each usb transaction
- //
- LOGGING( fwrite( pb->ioBuffer, sizeof(char), pb->ioReqCount, logfile ) );
- }
- else
- {
- USBExpertStatus(usbprint->usbReference, "\p" kStrPrinterClass "Write to unopened pipe" , usbprint->usbStatus );
- pb->ioResult = abortErr;
- }
- }
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: Abort
-
- Input Parameters:
- refNum DRVR refnum
- pPrinterPB current printing device class's storage
-
- Output Parameters:
-
- Description:
- Asynchronous completion.
- Note: USBAbortPipeByReference can leave the data toggle in the wrong state.
- We need to abort both pipes, and then the client must soft reset the printer
- to get the printer's data toggles correct.
- We prematurely call completion routines for active i/o so that CloseDriverSync
- will not hang the system after an abort, including hot unplug. This works out okay,
- since the request will be dequeued now, and when the i/o actually terminates
- the system will be called with an invalid queue element and then reject this second
- attempt to dequeue the i/o.
-
- Change History:
- 4 Aug 1998, oja: abort both pipes, call completion routines
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- OSStatus
- Abort( DriverRefNum refNum, struct usbPrinterPBStruct *pPrinterPB )
- {
- OSStatus err = noErr;
-
-
- refNum = 0; // unused
- //
- // if there's any pending io this will call the completion routine
- //
- err = USBAbortPipeByReference( pPrinterPB->writePipeRef );
- err = USBAbortPipeByReference( pPrinterPB->readPipeRef );
-
- if ( pPrinterPB->out.usbCompletion != (USBCompletion) NULL )
- CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->writeDrvr.pb, pPrinterPB->writeDrvr.ctl );
- if ( pPrinterPB->in.usbCompletion != (USBCompletion) NULL )
- CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->readDrvr.pb, pPrinterPB->readDrvr.ctl );
- return err;
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: CompletionProc
-
- Input Parameters:
- pb USB param block ptr
-
- Output Parameters:
-
- Description:
- Asynchronous completion routine for DRVR requests.
-
- Change History:
- 10 Aug 1998, oja: if error, do not set clientParam's ioResult
- explicitly (wait for JIODone)
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- CompletionProc(USBPB *pb)
- {
- // call the user completion routine
- struct usbPrinterPBStruct
- *pPrinterPB = (struct usbPrinterPBStruct *) pb->usbRefcon;
- IOParamPtr clientParam = pPrinterPB->statusDrvr.pb;
-
- clientParam->ioActCount = pb->usbActCount;
-
- if ( pb->usbStatus != noErr )
- {
- USBClearPipeStallByReference(pb->usbReference); // we got an error, try to clear any stalls
-
- IF_DEBUG( USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass "CompletionProc Error" , pb->usbStatus ) );
- IF_DEBUG( USBExpertStatus(pPrinterPB->deviceRef, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
- }
-
- pb->usbCompletion = (USBCompletion) NULL; // checked by Finalize
- if ( pPrinterPB->statusDrvr.ctl != NULL )
- CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->statusDrvr.ctl );
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: CentronicsStatus
-
- Input Parameters:
- pb MacOS device manager parameter block
- ctl device manager dCtl block
- pPrinterPB current printing device class's storage
-
- Output Parameters:
- pStatusByte
-
- Description:
- setup the device request for a USB printer class request one byte status.
-
- Change History:
- 29 Jun 1998, oja: called from StatusControlRequests, change params
- 26 Jun 1998, oja: changed params to be consistent w/ Read & Write
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- static void
- CentronicsStatus( USBPB *usbprint, Ptr buffer, short interfaceNumber )
- {
- usbprint->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
-
- usbprint->usb.cntl.BRequest = kUSBPrintClassGetCentronicsStatus;
- usbprint->usb.cntl.WValue = 0;
- usbprint->usb.cntl.WIndex = interfaceNumber;
-
- usbprint->usbReqCount = 1;
- usbprint->usbBuffer = buffer;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: SoftReset
-
- Input Parameters:
- usbprint USB param block
- interfaceNumber
-
- Output Parameters:
-
- Description:
- Setup the device request for a USB printer class request soft reset.
-
- Change History:
- 29 Jun 1998, oja: called from StatusControlRequests, change params
- 26 Jun 1998, oja: changed params to be consistent w/ Read & Write
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- SoftReset( USBPB *usbprint, short interfaceNumber )
- {
- usbprint->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBOther);
-
- usbprint->usb.cntl.BRequest = kUSBPrintClassSoftReset;
- usbprint->usb.cntl.WValue = 0;
- usbprint->usb.cntl.WIndex = interfaceNumber;
-
- usbprint->usbReqCount = 0;
- usbprint->usbBuffer = NULL;
-
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: CapabilityRequest
-
- Input Parameters:
- usbprint USB parameter block
- p result pointer
- length amount of data allocated
- config
- interfaceNum
- alternateSetting
-
-
- Output Parameters:
- p result pointer
- length amount of data allocated
-
- Description:
- setup the device request for a USB printer class request 1284 id string.
-
- Change History:
- 29 Jun 1998, oja: called from StatusControlRequests, change params
- 26 Jun 1998, oja: changed params to be consistent w/ Read & Write
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- CapabilityRequest( USBPB *pb, Ptr p, long length, short configValue, short interfaceNumber, short alternateSetting )
- {
-
- pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
-
- pb->usb.cntl.BRequest = kUSBPrintClassGetDeviceID;
- pb->usb.cntl.WValue = configValue; // configuration
- pb->usb.cntl.WIndex = (interfaceNumber<<8) | alternateSetting;
-
- pb->usbReqCount = length;
- pb->usbBuffer = p;
-
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: StatusControlRequests
-
- Input Parameters:
- pb MacOS device manager parameter block
- ctl device manager dCtl block
- pPrinterPB current printing device class's storage
-
- Output Parameters:
-
- Description:
- Asynchronous completion.
-
- Change History:
- 26 Jun 1998, oja: changed params to be consistent w/ Read & Write
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
- void
- ControlStatusRequests( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
- {
-
- //
- // queue a transaction to retrieve the centronics status
- //
- OSStatus err;
- USBPB *usbprint = &pPrinterPB->pb;
- Boolean dosomething = false;
-
- #if DEBUG
- Str255 text;
-
- sprintf( (char *)text, " PrinterClass ControlStatus: %d", ((CntrlParam *) pb)->csCode );
- text[0] = cstrlen((char *)text); // c2pstr
- USBExpertStatus(usbprint->usbReference, text, usbprint->usbStatus );
- #endif
-
- switch( ((CntrlParam *) pb)->csCode )
- {
- case kDrvrCentronicsStatus:
- dosomething = true;
- CentronicsStatus( usbprint, *((Ptr *)((CntrlParam *) pb)->csParam), pPrinterPB->interfaceNumber );
- break;
- case kDrvr1284IdString:
- dosomething = true;
- CapabilityRequest( usbprint,
- *((Ptr *)((CntrlParam *) pb)->csParam),
- *((long *) &((CntrlParam *) pb)->csParam[4]),
- pPrinterPB->configurationNumber, // configuration
- pPrinterPB->interfaceNumber,
- pPrinterPB->alternateSetting);
- break;
- case kDrvrSoftReset:
- dosomething = true;
- SoftReset( usbprint, pPrinterPB->interfaceNumber );
- break;
- default:
- break;
- }
-
- if ( !dosomething )
- pb->ioResult = paramErr;
- else
- {
- SetNullUSBParamBlock(pPrinterPB->deviceRef, usbprint );
- usbprint->usbBuffer = 0;
- usbprint->usbActCount = 0;
- usbprint->usbReqCount = 0;
- usbprint->usbCompletion = (USBCompletion)CompletionProc;
- usbprint->usbRefcon = (unsigned long) pPrinterPB;
-
- pb->ioResult = ioInProgress;
- pPrinterPB->statusDrvr.pb = pb;
- pPrinterPB->statusDrvr.ctl = ctl;
-
- err = USBDeviceRequest(usbprint);
- if(immediateError(err))
- {
- USBExpertFatalError(usbprint->usbReference, err, "\p" kStrPrinterClass "StatusControlRequests", 0);
- pb->ioResult = err;
- }
- }
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: PrinterDeviceCompletionProc
-
- Input Parameters:
- pb refCon tells which state we're completing
-
- Output Parameters:
- <none>
-
- Description:
- Complete asynch transactions initiated by PrinterDeviceInitiateTransaction.
-
- Change History:
- 17 Aug 1998, oja: don't retry high level errors (support hot unplug of root hub)
- 20 Jul 1998, oja: clear pipe stall before retrying
- 15 May 1998, oja: added missing break for GetCapabilityString
- reworked GetFullConfiguration to properly handle case
- where there's only one interface
- 26 Mar 1998, oja: set info 1 to DEBUG StateStr
- (distinguishes completion from initiate)
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-
- static void
- PrinterDeviceCompletionProc(USBPB *pb)
- {
- register struct usbPrinterPBStruct *pPrinterPB;
- OSStatus err;
-
-
- pPrinterPB = (struct usbPrinterPBStruct *)(pb);
-
- pPrinterPB->transDepth--;
- if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
- {
- USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "CompletionProc Illegal Transaction Depth", pPrinterPB->transDepth );
- }
-
- IF_DEBUG( USBExpertStatus(pPrinterPB->deviceRef, StateStr(pPrinterPB->pb.usbRefcon, kPString) , 1 ) );
-
- pPrinterPB->delayInProgress = false;
-
- if ( pPrinterPB->terminating )
- {
- // if we've been hot unplugged
- // don't startup any new transactions
- // allow PrintDriverFinalize to continue
- pPrinterPB->pb.usbStatus = kUSBAbortedError;
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
-
-
- switch( pPrinterPB->pb.usbStatus )
- {
- case kUSBPending:
- case noErr:
- pPrinterPB->pb.usbRefcon &= ~kRetryTransaction;
- pPrinterPB->retryCount = kPrinterRetryCount;
- break;
-
- case kUSBLinkErr:
- case kUSBCRCErr: /* Pipe stall, bad CRC */
- case kUSBBitstufErr: /* Pipe stall, bitstuffing */
- case kUSBDataToggleErr: /* Pipe stall, Bad data toggle */
- case kUSBNotRespondingErr: /* Pipe stall, No device, device hung */
- case kUSBPIDCheckErr: /* Pipe stall, PID CRC error */
- case kUSBWrongPIDErr: /* Pipe stall, Bad or wrong PID */
-
- USBClearPipeStallByReference(pPrinterPB->deviceRef); // we got an error, try to clear any stalls
- USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass " retry", pPrinterPB->pb.usbStatus);
-
- // clear out the transaction pending flag
- pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
- pPrinterPB->pb.usbRefcon |= kRetryTransaction;
- pPrinterPB->retryCount--;
- if (!pPrinterPB->retryCount)
- {
- USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "Retry failed", pPrinterPB->pb.usbRefcon & ~kRetryTransaction);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- else
- {
- pPrinterPB->pb.usbStatus = noErr; // let's retry one more time
- }
- break;
-
- case kUSBNotFound:
- break;
-
- case kUSBAbortedError: /* user cancel, or hot unplug */
- default:
- // clear out the transaction pending flag
- pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
- pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- break;
- }
-
- if (pPrinterPB->pb.usbRefcon & kTransactionPending)
- {
- int length;
-
- //
- // advance to the next state
- //
- pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
- switch(pPrinterPB->pb.usbRefcon)
- {
- case kFindInterface_bidirectional:
- USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"kFindInterface_bidirectional completed", pPrinterPB->pb.usb.cntl.WIndex);
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- if ((pPrinterPB->pb.usbClassType == kUSBPrintingClass) &&
- (pPrinterPB->pb.usbSubclass == kUSBPrinterSubclass) &&
- (pPrinterPB->pb.usbProtocol == kUSBPrinterBidirectionalProtocol))
- {
- USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"Found bidirection interface at alt setting ", pPrinterPB->pb.usbOther);
- pPrinterPB->configurationNumber = pPrinterPB->pb.usb.cntl.WValue;
- pPrinterPB->alternateSetting = pPrinterPB->pb.usbOther;
- pPrinterPB->printerProtocol = kUSBPrinterBidirectionalProtocol;
- if (pPrinterPB->pInterfaceDescriptor)
- {
- if (pPrinterPB->interfaceNumber == pPrinterPB->pb.usb.cntl.WIndex)
- {
- pPrinterPB->pb.usbRefcon = kSetInterface;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_Bidirectional didn't find the right interface", 0);
- }
- }
- else
- {
- pPrinterPB->pb.usbRefcon = kOpenDevice;
- pPrinterPB->interfaceNumber = pPrinterPB->pb.usb.cntl.WIndex;
- }
- }
- }
- else
- {
- if ( pPrinterPB->pb.usbStatus == kUSBNotFound )
- {
- USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"Bidirectional interface was not found", pPrinterPB->pb.usb.cntl.WIndex);
- pPrinterPB->pb.usbRefcon = kFindInterface_unidirectional;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_bidirectional failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- }
- break;
-
- case kFindInterface_unidirectional:
- USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"kFindInterface_bidirectional completed", pPrinterPB->pb.usb.cntl.WIndex);
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- if ((pPrinterPB->pb.usbClassType == kUSBPrintingClass) &&
- (pPrinterPB->pb.usbSubclass == kUSBPrinterSubclass) &&
- (pPrinterPB->pb.usbProtocol == kUSBPrinterBidirectionalProtocol))
- {
- USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"Found unidirection interface at alt setting ", pPrinterPB->pb.usbOther);
- pPrinterPB->pb.usbRefcon = kOpenDevice;
- pPrinterPB->configurationNumber = pPrinterPB->pb.usb.cntl.WValue;
- pPrinterPB->alternateSetting = pPrinterPB->pb.usbOther;
- pPrinterPB->printerProtocol = kUSBPrinterUnidirectionalProtocol;
- if (pPrinterPB->pInterfaceDescriptor)
- {
- if (pPrinterPB->interfaceNumber == pPrinterPB->pb.usb.cntl.WIndex)
- {
- pPrinterPB->pb.usbRefcon = kSetInterface;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_Unidirectional didn't find the right interface", 0);
- }
- }
- else
- {
- pPrinterPB->pb.usbRefcon = kOpenDevice;
- pPrinterPB->interfaceNumber = pPrinterPB->pb.usb.cntl.WIndex;
- }
- }
- }
- else
- {
- if ( pPrinterPB->pb.usbStatus == kUSBNotFound )
- {
- USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"Unidirectional interface was not found", pPrinterPB->pb.usb.cntl.WIndex);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_unidirectional failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- }
- break;
-
- case kOpenDevice:
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"kOpenDevice completed", pPrinterPB->pb.usbStatus);
- pPrinterPB->pb.usbRefcon = kNewInterfaceRef;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kOpenDevice failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kNewInterfaceRef:
- USBExpertStatus(pPrinterPB->deviceRef, "\p"kStrPrinterClass"kNewInterfaceRef completed", pPrinterPB->pb.usbReference);
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->interfaceRef = pPrinterPB->pb.usbReference;
- pPrinterPB->pb.usbRefcon = kSetInterface;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kNewInterfaceRef failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kSetInterface:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kSetInterface completed", 0);
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->pb.usbRefcon = kConfigureInterface;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kSetInterface failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kConfigureInterface:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kConfigureInterface completed, pipes = ", pPrinterPB->pb.usbOther);
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->pipeCount = pPrinterPB->pb.usbOther;
- pPrinterPB->pb.usbRefcon = kGetCapabilityString;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kConfigureInterface failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kGetCapabilityString:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kGetCapabilityString completed", pPrinterPB->pb.usbStatus);
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- //
- // In the short term (fall '98) several vendors are planning on shipping
- // devices with a parallel port and using the Lucent USS-720 USB-to-parallel hardware.
- // Unfortunately this isn't an ideal solution from the USB perspective:
- // users can leave the printer off while the cable responds that there's
- // a printer connected. Then we have no way of using the DEVICE_ID
- // string to tag the printer and register it.
- // To alleviate this situation, we repeatedly poll the USS-720 if the DEVICE_ID
- // string is null. Every few seconds we'll retry this state.
- // At some point the user wants to print and switches on the printer. The class
- // driver then picks up from here and registers the device properly.
- //
- length = pPrinterPB->pCapabilityString[1] | (pPrinterPB->pCapabilityString[0] << 8);
- if ( IsLucentCable( &pPrinterPB->deviceDescriptor ) && pPrinterPB->pb.usbActCount == 0 )
- pPrinterPB->pb.usbRefcon = kDelayGetCapability;
- else
- pPrinterPB->pb.usbRefcon = kFindBulkOutPipe;
- }
- else
- {
- if ( pPrinterPB->pb.usbStatus == kUSBOverRunErr )
- {
- //
- // if we've haven't managed to read the whole capability string
- // we need to allocate memory and read it in by initiating kGetFullCapabilityString
- //
- length = pPrinterPB->pCapabilityString[1] | (pPrinterPB->pCapabilityString[0] << 8);
-
- if ( length > sizeof(pPrinterPB->capability) &&
- pPrinterPB->pb.usbRefcon == kGetCapabilityString )
- pPrinterPB->pb.usbRefcon = kAllocateCapabilityMem;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kGetCapabilityString failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- }
- break;
-
- case kDelayGetCapability:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kDelayGetCapability completed", pPrinterPB->pb.usbStatus);
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->pb.usbRefcon = kGetCapabilityString;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kDelayGetCapability failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kAllocateCapabilityMem:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kAllocateCapabilityMem completed", pPrinterPB->pb.usbStatus);
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->pCapabilityString = pPrinterPB->pb.usbBuffer;
- pPrinterPB->pb.usbRefcon = kGetFullCapabilityString;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kAllocateCapabilityMem failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kGetFullCapabilityString:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kGetFullCapabilityString completed", pPrinterPB->pb.usbStatus);
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->pb.usbRefcon = kGetInterface;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kGetFullCapabilityString failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kGetInterface:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kGetInterface completed", pPrinterPB->pb.usbStatus);
- if (( pPrinterPB->pb.usbStatus == noErr ) && (pPrinterPB->whichAltInterface == pPrinterPB->alternateSetting))
- {
- pPrinterPB->pb.usbRefcon = kFindBulkOutPipe;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kGetInterface - wrong interface selected", pPrinterPB->whichAltInterface);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kFindBulkOutPipe:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kFindBulkOutPipe completed", pPrinterPB->pb.usbReference);
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->writePipeRef = pPrinterPB->pb.usbReference; // remember the ref
- pPrinterPB->out = pPrinterPB->pb; // copy the paramblock
- pPrinterPB->out.usbCompletion = (USBCompletion) NULL; // for finalize
-
- if ( pPrinterPB->printerProtocol == kUSBPrinterBidirectionalProtocol )
- pPrinterPB->pb.usbRefcon = kFindBulkInPipe;
- else
- pPrinterPB->pb.usbRefcon = kTaskTimeRequired;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindBulkOutPipe failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kFindBulkInPipe:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kFindBulkInPipe completed", pPrinterPB->pb.usbReference);
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->readPipeRef = pPrinterPB->pb.usbReference;
- pPrinterPB->in = pPrinterPB->pb; // copy the paramblock
- pPrinterPB->in.usbCompletion = (USBCompletion) NULL; // for finalize
-
- pPrinterPB->pb.usbRefcon = kTaskTimeRequired;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindBulkInPipe failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kTaskTimeRequired:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kTaskTimeRequired completed (now at task time)", pPrinterPB->pb.usbReference);
- //
- // once we know what device we're dealing with
- // open the i/o channel(s) to the device
- // and enter it in the name registry
- //
- err = InstallDrivers( pPrinterPB );
- if ( err == noErr )
- {
- USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kTaskTimeRequired - drivers installed", pPrinterPB->pb.usbReference);
- err = RegisterDevice( pPrinterPB );
- if ( err == noErr )
- {
- USBExpertStatus(pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kTaskTimeRequired - RegisterDevice successful", pPrinterPB->pb.usbReference);
- }
- else
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, err, "\p" kStrPrinterClass "kTaskTimeRequired - RegisterDevice failed", 0);
- }
- }
- else
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, err, "\p" kStrPrinterClass "kTaskTimeRequired - InstallDrivers failed", 0);
- }
-
- pPrinterPB->pb.usbCompletion = (USBCompletion) NULL; // Finalize
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->pb.usbRefcon = kGetCentronicsStatus;
- pPrinterPB->printerConfigured = true;
- }
- else
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "RegisterDevice failed", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kGetCentronicsStatus:
- //
- // if InitiateTransaction fell through on it's kTaskTimeRequired case we'll end up here
- //
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- #if DEBUG
- Str255 text, te;
- hexstr( sizeof(char), &pPrinterPB->centronics.b, (char *) te );
- sprintf( (char *)text, " PrinterClass Status: %s", te );
- text[0] = cstrlen((char *)text); // c2pstr
- USBExpertStatus(pPrinterPB->interfaceRef, text, pb->usbStatus );
- #endif
- #if DEBUG
- if ( !pPrinterPB->centronics.status.notError )
- {
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass "Error at printer", pPrinterPB->pb.usbStatus);
- }
- if ( pPrinterPB->centronics.status.paperError )
- {
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass "Check paper", pPrinterPB->pb.usbStatus);
- }
- if ( !pPrinterPB->centronics.status.select )
- {
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass "printer offline", pPrinterPB->pb.usbStatus);
- }
- #endif
- pPrinterPB->pb.usbRefcon = kDelayGetCentronicsStatus;
- }
- break;
-
- case kDelayGetCentronicsStatus:
- //
- // loop around continually getting status
- //
- if ( pPrinterPB->pb.usbStatus == noErr )
- {
- pPrinterPB->pb.usbRefcon = kGetCentronicsStatus;
- }
- break;
- case kNilCompletion:
- default:
- if ( pPrinterPB->pb.usbStatus == noErr )
- pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
- break;
- }
- }
-
- // did the removal notification get called? If so, don't start another transaction. Just exit
- if (!pPrinterPB->terminating)
- {
- if (pPrinterPB->pb.usbStatus == noErr )
- {
- if (!(pPrinterPB->pb.usbRefcon & kReturnFromDriver))
- PrinterDeviceInitiateTransaction(pb);
- }
- else if ( pPrinterPB->pb.usbRefcon & kReturnFromDriver)
- {
- USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, StateStr(pPrinterPB->pb.usbRefcon, kPString), pPrinterPB->pb.usbRefcon);
- USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, USBStatusStr(pPrinterPB->pb.usbStatus, kPString), 0);
- }
- }
- else
- {
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
-
- // If we're exiting the driver, then make certain the completion routine is set to NULL
- // this lets the driver removal task know that there's nothing pending.
- if ( pPrinterPB->pb.usbRefcon & kReturnFromDriver)
- {
- pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: PrinterDeviceInitiateTransaction
-
- Input Parameters:
- pb USB parameter block
-
- Output Parameters:
-
- Description:
- Since USB transactions are asynchronous we use the refCon field
- in the parameter block to implement the following logic via a state machine.
-
- Start out by getting the device configuration descriptor
- If the device has more than one printing interface
- If a bidirectional interface exists
- select it
- Else
- select the (mandatory) unidirectional interface
- Get the (manadatory) 1284 capability string
- Open pipes to the BulkOut (and optional BulkIn) endpoints
- Install read and write drivers in the unit table
- Using information from the capability string
- enter the printer in the MacOS name registry.
-
-
- Change History:
- 15 May 1998, oja: cleanup error/status messages
- handle setinterface correctly if only one
- interface is available
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- PrinterDeviceInitiateTransaction(USBPB *pb)
- {
- register struct usbPrinterPBStruct *pPrinterPB;
- int length;
- OSStatus err;
-
- pPrinterPB = (struct usbPrinterPBStruct *)(pb);
-
- pPrinterPB->transDepth++;
- if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
- {
- USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction illegal transaction depth", 0);
- }
- IF_DEBUG( USBExpertStatus( pPrinterPB->deviceRef, StateStr(pPrinterPB->pb.usbRefcon, kPString), 0) );
-
- pPrinterPB->delayInProgress = false;
- switch(pPrinterPB->pb.usbRefcon & ~kRetryTransaction)
- {
- case kFindInterface_bidirectional:
- USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass"kFindInterface_bidirectional", 0);
- SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
-
- pPrinterPB->pb.usbBuffer = 0;
- pPrinterPB->pb.usbActCount = 0;
- pPrinterPB->pb.usbReqCount = 0;
- pPrinterPB->pb.usb.cntl.WIndex = 0;
- pPrinterPB->pb.usb.cntl.WValue = 0;
- pPrinterPB->pb.usbClassType = kUSBPrintingClass;
- pPrinterPB->pb.usbSubclass = kUSBPrinterSubclass;
- pPrinterPB->pb.usbProtocol = kUSBPrinterBidirectionalProtocol;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- err = USBFindNextInterface(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"kFindInterface_bidirectional - immediate error", err);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kFindInterface_unidirectional:
- USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass"kFindInterface_unidirectional", 0);
- SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
-
- pPrinterPB->pb.usbBuffer = 0;
- pPrinterPB->pb.usbActCount = 0;
- pPrinterPB->pb.usbReqCount = 0;
- pPrinterPB->pb.usb.cntl.WIndex = 0;
- pPrinterPB->pb.usb.cntl.WValue = 0;
- pPrinterPB->pb.usbClassType = kUSBPrintingClass;
- pPrinterPB->pb.usbSubclass = kUSBPrinterSubclass;
- pPrinterPB->pb.usbProtocol = kUSBPrinterUnidirectionalProtocol;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- err = USBFindNextInterface(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"kFindInterface_unidirectional - immediate error", err);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kOpenDevice:
- USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass"kOpenDevice", 0);
- SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
-
- pPrinterPB->pb.usbBuffer = 0;
- pPrinterPB->pb.usbActCount = 0;
- pPrinterPB->pb.usbReqCount = 0;
- pPrinterPB->pb.usb.cntl.WValue = pPrinterPB->configurationNumber;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- err = USBOpenDevice(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"USBOpenDevice - immediate error", err);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kNewInterfaceRef:
- USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass"kNewInterfaceRef for interface number", pPrinterPB->interfaceNumber);
- SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
-
- pPrinterPB->pb.usbBuffer = 0;
- pPrinterPB->pb.usbActCount = 0;
- pPrinterPB->pb.usbReqCount = 0;
- pPrinterPB->pb.usb.cntl.WIndex = pPrinterPB->interfaceNumber;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- err = USBNewInterfaceRef(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"USBNewInterfaceRef - immediate error", err);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
-
- case kSetInterface:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kSetInterface to alternate setting", pPrinterPB->alternateSetting);
- SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
-
- pPrinterPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBInterface);
-
- pPrinterPB->pb.usb.cntl.BRequest = kUSBRqSetInterface;
- pPrinterPB->pb.usb.cntl.WValue = pPrinterPB->alternateSetting; // alternate setting
- pPrinterPB->pb.usb.cntl.WIndex = pPrinterPB->interfaceNumber; // interface
-
- pPrinterPB->pb.usbReqCount = 0;
- pPrinterPB->pb.usbBuffer = NULL;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- err = USBDeviceRequest(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"kSetInterface - immediate error", err);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
-
- case kConfigureInterface:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kConfigureInterface for alternate setting", pPrinterPB->alternateSetting);
- SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
-
- pPrinterPB->pb.usbBuffer = 0;
- pPrinterPB->pb.usbActCount = 0;
- pPrinterPB->pb.usbReqCount = 0;
- pPrinterPB->pb.usbOther = pPrinterPB->alternateSetting;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- err = USBConfigureInterface(pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"USBConfigureInterface - immediate error)", err);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kGetCapabilityString:
- //
- // once the interface (and alternate) is assinged
- // we can retreive the 1284 capability string to see what kind of printer
- // is attached
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kGetCapabilityString", 0);
- pPrinterPB->pCapabilityString = pPrinterPB->capability;
- GetCapability( pPrinterPB, pPrinterPB->pCapabilityString, sizeof(pPrinterPB->capability) );
- break;
-
- case kDelayGetCapability:
- //
- // USS-720 USB-parallel cable: couldn't get the capability string because the printer is off
- // Delay a few seconds and try again.
- // Will succeed when the user turns the printer on.
- //
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kDelayGetCapability", 0);
- SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
-
- pPrinterPB->pb.usbBuffer = 0;
- pPrinterPB->pb.usbActCount = 0;
- pPrinterPB->pb.usbReqCount = kUSS720MillisecondDelay;
- pPrinterPB->pb.usbFlags = kUSBTaskTimeFlag;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- pPrinterPB->delayInProgress = true;
- err = USBDelay(&pPrinterPB->pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCapability - immediate error", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kAllocateCapabilityMem:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kAllocateCapabilityMem", 0);
- SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
-
- length = pPrinterPB->capability[1] | (pPrinterPB->capability[0]<<8);
- pPrinterPB->pb.usbBuffer = 0;
- pPrinterPB->pb.usbActCount = 0;
- pPrinterPB->pb.usbReqCount = length;
- pPrinterPB->pb.usbFlags = 0;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- err = USBAllocMem(&pPrinterPB->pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kAllocateCapabilityMem - immediate error", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kGetFullCapabilityString:
- //
- // the capability string was too long to fit in the statically allocated space
- // need to release this memory when we finalize our driver
- //
-
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kGetFullCapabilityString", 0);
- length = pPrinterPB->capability[1] | (pPrinterPB->capability[0]<<8);
- if ( pPrinterPB->pCapabilityString )
- GetCapability( pPrinterPB, pPrinterPB->pCapabilityString, length );
- else
- USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, "\p" kStrPrinterClass "Can't allocate capability memory", 0);
- break;
-
- case kGetInterface:
- // failsafe check that we've got the right setup
- // it's possible the device didn't respond to our SetInterface
- GetInterface( &pPrinterPB->pb, &pPrinterPB->whichAltInterface );
- break;
-
- case kFindBulkOutPipe:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kFindBulkOutPipe", 0);
- SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
-
- pPrinterPB->pb.usbBuffer = 0;
- pPrinterPB->pb.usbActCount = 0;
- pPrinterPB->pb.usbReqCount = 0;
- pPrinterPB->pb.usbFlags = kUSBOut;
- pPrinterPB->pb.usbClassType = kUSBBulk;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- err = USBFindNextPipe( &pPrinterPB->pb );
- if (immediateError(err))
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, kStrPrinterClass"kFindBulkOutPipe - immediate error", err);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kFindBulkInPipe:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kFindBulkInPipe", 0);
- SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
-
- pPrinterPB->pb.usbBuffer = 0;
- pPrinterPB->pb.usbActCount = 0;
- pPrinterPB->pb.usbReqCount = 0;
- pPrinterPB->pb.usbFlags = kUSBIn;
- pPrinterPB->pb.usbClassType = kUSBBulk;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- err = USBFindNextPipe( &pPrinterPB->pb );
- if (immediateError(err))
- {
- USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, "\p"kStrPrinterClass"kFindBulkInPipe - immediate error", err);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kTaskTimeRequired:
- USBExpertStatus(pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kTaskTimeRequired", 0);
- // to stress test usb bus, fallthrough to kGetCentronicsStatus
- SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
-
- pPrinterPB->pb.usbBuffer = 0;
- pPrinterPB->pb.usbActCount = 0;
- pPrinterPB->pb.usbReqCount = kUSBNoDelay;
- pPrinterPB->pb.usbFlags = kUSBTaskTimeFlag;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- pPrinterPB->delayInProgress = true;
- err = USBDelay(&pPrinterPB->pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kTaskTimeRequired - immediate error", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kGetCentronicsStatus:
- SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
-
- CentronicsStatus( &pPrinterPB->pb, &pPrinterPB->centronics.b, pPrinterPB->interfaceNumber );
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- err = USBDeviceRequest(&pPrinterPB->pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kGetCentronicsStatus Immediate error", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- case kDelayGetCentronicsStatus:
- SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
-
- pPrinterPB->pb.usbBuffer = 0;
- pPrinterPB->pb.usbActCount = 0;
- pPrinterPB->pb.usbReqCount = kUSS720StatusMSDelay;
-
- pPrinterPB->pb.usbRefcon |= kTransactionPending;
- pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
- pPrinterPB->delayInProgress = true;
- err = USBDelay(&pPrinterPB->pb);
- if(immediateError(err))
- {
- USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCentronicsStatus - immediate error", 0);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- }
- break;
-
- default:
- USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction - unknown state", pPrinterPB->pb.usbRefcon);
- pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
- break;
- }
-
- if (pPrinterPB->pb.usbRefcon & kReturnFromDriver)
- {
- pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
- }
- }
-
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: PrintDriverEntry
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
- This is where the system instantiates a USB printing device.
-
- We need to install drivers in the MacOS unitTable, and a reference
- in the name registry.
-
- But the information we need to do this is only available after some
- USB transactions have completed. So we initiate here a series of asynchronous
- USB operations to get that information (by calling the first
-
- Change History:
- 31 Jul 1998, oja: page-aligned double buffer i/o
- 30 Jun 1998, oja: change CentronicsStatus to ControlStatusRequests
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- void
- PrintDriverEntry(
- USBDeviceRef deviceRef,
- USBDeviceDescriptorPtr pDeviceDesc,
- USBInterfaceDescriptorPtr pInterfaceDesc,
- UInt32 interfaceNumber
- )
- {
- static Boolean beenThereDoneThat = false;
- OSStatus err;
-
-
- RoutineDescriptor qw = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBWriteProcInfo, QueueWrite);
- RoutineDescriptor qr = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBReadProcInfo, QueueRead);
- RoutineDescriptor qa = BUILD_ROUTINE_DESCRIPTOR( uppAbortProcInfo, Abort);
- RoutineDescriptor qs = BUILD_ROUTINE_DESCRIPTOR( uppControlStatusProcInfo, ControlStatusRequests );
-
- if( !beenThereDoneThat)
- {
- beenThereDoneThat = true;
-
- //DebugStr("\pIn Printer Driver Entry");
- USBExpertStatus(deviceRef, "\p"kStrPrinterClass"Starting USB Printer Driver", 0);
-
- printerClassRecord.deviceDescriptor = *pDeviceDesc; /* keep a copy of the device descriptor */
- printerClassRecord.pInterfaceDescriptor = pInterfaceDesc;
- printerClassRecord.interfaceNumber = interfaceNumber;
-
- printerClassRecord.deviceRef = deviceRef;
- printerClassRecord.interfaceRef = deviceRef;
-
- printerClassRecord.transDepth = 0; /* init Delay Callback Depth */
-
- printerClassRecord.inRefNum = -1; /* initially no DRVRs added to UnitTable */
- printerClassRecord.outRefNum = -1;
- err = LoadResources( &printerClassRecord );
- if ( err != noErr )
- USBExpertFatalError( deviceRef, err, "\p" kStrPrinterClass "LoadResources failed", 0);
- //
- // routines to write and read to the device must be called by 68K DRVR
- // so we use mixed-mode manager to dispatch between PPC and 68K
- //
- printerClassRecord.qwrite = (QueueUSBWriteUPP) &printerClassRecord.qwriteRD;
- printerClassRecord.qwriteRD = qw;
-
- printerClassRecord.qread = (QueueUSBReadUPP) &printerClassRecord.qreadRD;
- printerClassRecord.qreadRD = qr;
-
- printerClassRecord.qstatus = (ControlStatusUPP) &printerClassRecord.qstatusRD;
- printerClassRecord.qstatusRD = qs;
-
- printerClassRecord.qabort = (AbortUPP) &printerClassRecord.qabortRD;
- printerClassRecord.qabortRD = qa;
-
- printerClassRecord.r = (QueueUSBReadUPP) QueueRead;
- printerClassRecord.w = (QueueUSBWriteUPP) QueueWrite;
- printerClassRecord.s = (ControlStatusUPP) ControlStatusRequests;
- printerClassRecord.a = (AbortUPP) Abort;
-
- SetNullUSBParamBlock( deviceRef, &printerClassRecord.pb );
- SetNullUSBParamBlock( 0, &printerClassRecord.in ); // fill in pipe ref later
- SetNullUSBParamBlock( 0, &printerClassRecord.out ); // fill in pipe ref later
-
- #if DOUBLE_BUFFER
- //
- // Assume 1. TRANSFER_SIZE is a power of 2
- // Assume 2. malignedBuffer is allocated to be 3*TRANSFER_SIZE
- //
- printerClassRecord.pageWriteAlignedBufferSize = TRANSFER_SIZE; // should get this from VM
- printerClassRecord.pageWriteAlignedBuffer = printerClassRecord.malignedBuffer;
- // align it below the buffer, then bring it into the range of the buffer
- *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) &= ~(printerClassRecord.pageWriteAlignedBufferSize - 1); //assumption1
- *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) += printerClassRecord.pageWriteAlignedBufferSize; //assumption2
-
- printerClassRecord.pageReadAlignedBufferSize = TRANSFER_SIZE;
- printerClassRecord.pageReadAlignedBuffer = printerClassRecord.pageWriteAlignedBuffer + TRANSFER_SIZE;
- #endif
- printerClassRecord.terminating = false;
- printerClassRecord.printerConfigured = false;
-
- //
- // Just to be thorough, lets hold our paramter blocks so that we won't page them at
- // interrupt time. (We should be in the System heap and automatically held.)
- //
- HoldMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
-
-
- //
- // Start out at first state
- //
- printerClassRecord.pCapabilityString = printerClassRecord.capability;
- printerClassRecord.pb.usbRefcon = kFindInterface_bidirectional;
- PrinterDeviceInitiateTransaction(&printerClassRecord.pb);
- }
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: PrinterRemovalNotification
-
- Input Parameters:
-
- Output Parameters:
-
- Description:
- release any allocated storage
- remove DRVRs from the UnitTable
-
- One small complication happens when the USS-720 cable is used. It's possible
- that the user has the device plugged in, but the printer wasn't powered on.
- In this case, our state machine is still cycling between the states
- kDelayGetCapability and kGetCapabilityString. If we terminate before the delay
- returns we'll crash the system. We monitor terminating to handle this
-
- Change History:
- 17 Aug 1998, oja: don't deregister if the root hub was hot unplugged
- 10 Aug 1998, oja: call Abort to cleanup pending read/write transactions
- 31 Jul 1998, oja: cleanup some hotplugging problems
- 12 Jul 1998, oja: allow for hot unplugging during initial startup
- wait for completion if refCon indicates some
- transaction is in progress
- 24 Apr 1998, oja: added call to DeregisterDevice
- 28 Feb 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- OSStatus
- PrinterRemovalNotification( void )
- {
- static Boolean logfileclosed = false;
- static Boolean aborted = false;
- static Boolean deregistered = false;
- static Boolean readpipeaborted = false;
- static Boolean writepipeaborted = false;
- static Boolean timedout = false;
- OSStatus result = noErr;
- static unsigned long tc = 0;
- //
- // notify state machine not to continue
- //
- printerClassRecord.terminating = true;
-
- USBExpertStatus( printerClassRecord.deviceRef, "\p"kStrPrinterClass"Driver removal notification received", 0);
- if (!logfileclosed)
- {
- LOGGING( fclose( logfile ) );
- logfileclosed = true;
- return (OSStatus) kUSBDeviceBusy;
- }
-
- // per the Mac OS USB DDK API Ref
- // "If the device associated with this call [USBDelay] is unplugged and its driver removed while
- // this function call is pending, the function will not complete."
- // therefore don't hang around if a delay is in progress
- if (( printerClassRecord.pb.usbCompletion != (USBCompletion) NULL ) && (!printerClassRecord.delayInProgress))
- {
- USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Waiting for configuration to complete", printerClassRecord.pb.usbRefcon);
- return (OSStatus) kUSBDeviceBusy;
- }
-
- // Abort any outstanding write requests
- if (( printerClassRecord.out.usbCompletion != (USBCompletion) NULL ) && (!writepipeaborted))
- {
- USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Abort write pipe", printerClassRecord.writePipeRef);
- USBAbortPipeByReference( printerClassRecord.writePipeRef );
- writepipeaborted = true;
- return (OSStatus) kUSBDeviceBusy;
- }
-
- // Abort any outstanding read requests
- if (( printerClassRecord.in.usbCompletion != (USBCompletion) NULL ) && (!readpipeaborted))
- {
- USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Abort read pipe", printerClassRecord.readPipeRef );
- USBAbortPipeByReference( printerClassRecord.readPipeRef );
- readpipeaborted = true;
- return (OSStatus) kUSBDeviceBusy;
- }
-
- // Abort any outstanding transactions
- if (!aborted)
- {
- USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Call Abort()", 0);
- Abort( 0, &printerClassRecord );
- aborted = true;
- return (OSStatus) kUSBDeviceBusy;
- }
-
- // wait up to ten seconds for the read & write routines to complete. When they do, the completion procptrs will be NULL'd
- if (tc == 0)
- tc = TickCount() + 10*60;
-
- if ( TickCount() >= tc )
- timedout = true;
-
- if (( TickCount() < tc ) &&
- (( printerClassRecord.out.usbCompletion != (USBCompletion) NULL) ||
- ( printerClassRecord.in.usbCompletion != (USBCompletion) NULL )))
- {
- return (OSStatus) kUSBDeviceBusy;
- }
-
- // Put the appropriate timeout message in the log
- if ( timedout )
- {
- USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"took longer than 10 seconds for read/write pipes to complete", 0);
- }
- else
- {
- USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Pipes closed normally", 0);
- }
-
- if (!deregistered)
- {
- //
- // remove printer from the name registry
- //
- USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Removed printer entry from nameregistry", 0);
- DeregisterDevice( &printerClassRecord );
- deregistered = true;
- return (OSStatus) kUSBDeviceBusy;
- }
-
- //
- // release any allocated storage
- //
- if ( printerClassRecord.pCapabilityString != printerClassRecord.capability )
- {
- USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Deallocated capability string memory", 0);
- printerClassRecord.pb.usbReference = printerClassRecord.deviceRef;
- printerClassRecord.pb.usbFlags = 0;
- printerClassRecord.pb.usbRefcon = kDeallocateCapbilityString;
- printerClassRecord.pb.usbBuffer = printerClassRecord.pCapabilityString;
- printerClassRecord.pb.usbCompletion = (USBCompletion)kUSBNoCallBack;
- printerClassRecord.delayInProgress = true; // this prevents the control pipe completion procptr from being checked
- USBDeallocMem(&printerClassRecord.pb);
-
- printerClassRecord.pCapabilityString = printerClassRecord.capability;
- return (OSStatus) kUSBDeviceBusy;
- }
-
- //
- // don't need to hang on to param blocks after we've gone away
- //
- UnholdMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
-
- USBExpertStatus(printerClassRecord.deviceRef, "\p"kStrPrinterClass"Ready for removal", 0);
- return kUSBNoErr;
- }
-
- /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Name: CFMInitialization
-
- Input Parameters:
- initBlock
-
- Output Parameters:
- printerClassDriverFileSpec set global
-
- Description:
- We use the code fragment initialization to get our filespec which
- LoadResources will use to open our resource fork.
-
- A peculiarity of the USB 1.0 implementation is that does not lock the
- driver into physical memory. As a result a driver which does not call
- SetDriverClosureMemory on it's fragment will likely be paged in during
- interrupt time and a double bus-fault will occur. The solution for this
- is to have the USB Expert call SetDriverClosureMemory in a future release
- of the USB stack. In the meantime, we call it on ourselves to lock us into
- physical memory. When the USB stack is revved, one call to SetDriverClosureMemory
- (either this one or the Expert's) will be treated as a NOP.
-
- Change History:
- 31 Jul 1998, oja: added call to SetDriverClosureMemory
- 11 Jun 1998, oja: Original version.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- OSErr
- CFMInitialization( CFragInitBlock *initBlock )
- {
- //
- // get a reference to our file so that we can open up the resource fork later on
- //
- if ( CFragHasFileLocation( initBlock->fragLocator.where ) )
- printerClassDriverFileSpec = *(initBlock->fragLocator.u.onDisk.fileSpec);
-
- // don't page us, we're a device driver
- return SetDriverClosureMemory( (CFragConnectionID) initBlock->closureID, true );
-
- }
-
- // eof
-